/***************************************************************************
 *   Copyright (C) 2004 by cyril dupuit                                    *
 *   cyrildupuit@hotmail.com                                               *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

//*****************************************************************************
// Nom du module : ProcInfo.c
// Description :  Obtention d'infos sur les processus.
//*****************************************************************************
 
// Historique :
// 28/10/04 : Creation du module V1.0  

#include "Kernel/Types.h"
#include "Arch/Pentium/Kernel/malloc.h"
#include "Kernel/Errors.h"
#include "Lib/StdLib/stdio.h"
#include "Lib/StdLib/string.h"

#include "FileSys/vfs/Vfs.h"
#include "FileSys/vfs/Mount.h"

#include "Lib/LinkList.h"
#include "Lib/Stack.h"

//*****************************************************************************

//*****************************************************************************

static void VfsMountDrawVerticalLines(VfsMountTree_t * pTree, LinkListID_t StackID);
static void VfsMountTreeDeleteObjects(LinkListID_t MountList, LinkListID_t StackID);

//*****************************************************************************
// But de la fonction : Afficher la liste des processus
// Entree : Aucune
// Parametre retourne : ERROR si memoire disponible insuffisante, TRUE sinon
//*****************************************************************************
Status_t VfsMountListShow(void)
{
	unsigned int Line = 0;
	unsigned int Count;
	QueueID_t QMountList;
	struct VfsMount * pMnt;
	
	Count = VfsMountCount();
	QMountList = QueueCreate(Count, QUEUE_FIFO);
	if(QMountList == 0)
	{//Creation de la file impossible
		SetLastError(INSUFFICIENT_MEMORY_AVAILABLE);
		return ERROR;
	}
	
	printf("Liste des systemes de fichiers montes (%d) : \n", Count);
	
	if(VfsMountGetList(QMountList) == FALSE)
	{//Une tache a ete cree entre temps, la file d'attente est trop petite
		printf("La liste ci-dessous est incomplete, un systeme de fichier vient d'etre monte !\n");
	}
	
	pMnt = (struct VfsMount *)QueueRead(QMountList);
	while(pMnt != NULL)
	{//Afficher la liste des systemes
		printf("%s\n", pMnt->pName);
		
		//Recuperer le prochain numero de processus
		pMnt = (struct VfsMount *)QueueRead(QMountList);
		Line = (Line + 1) % 20;//20 equivaut au nombre de ligne sur la console
		if((Line == 0)&&(pMnt != NULL))
		{//Demander a l'utilisateur de presser une touche pour voir la suite de l'ecran
			if(Pause() != TRUE)
			{//L'utilisateur stoppe la visualisation
				QueueDelete(&QMountList);
				
				return TRUE;
			}
		}
	}
	
	QueueDelete(&QMountList);
	
	return TRUE;
}

//*****************************************************************************
// But de la fonction : Afficher l'arbre des processus
// Entree : Aucune
// Parametre retourne : ERROR si memoire disponible insuffisante, TRUE sinon
//*****************************************************************************
Status_t VfsMountTreeShow(void)
{
	const char MSignF[] = {0xC3, 0xC4, 0xC4, 0xC4,'\0'};// |-
	const char MSignZ[] = {0xC0, 0xC4, 0xC4, 0xC4,'\0'};// '-
	const char MSignNone[] = "";
	LinkListID_t ProcessList;
	LNode_t * pPosition;
	VfsMountTree_t * pTree;
	unsigned int Line = 0;
	char * pSign;
	Count_t TreeCount;
	Status_t PrevStatus = 0;
	LinkListID_t StackID;
	
	ProcessList = VfsMountGetTree();
	if(ProcessList == 0)
	{//Memoire insuffisante
		SetLastError(INSUFFICIENT_MEMORY_AVAILABLE);
		return ERROR;
	}

	StackID = LinkListCreate();
	if(StackID == 0)
	{//Memoire insuffisante
		VfsMountTreeDeleteObjects(ProcessList, StackID);
		SetLastError(INSUFFICIENT_MEMORY_AVAILABLE);
		return ERROR;
	}
	
	//Connaitre le nombre d'element dans la liste
	TreeCount = LinkListGetCount(ProcessList);

	if(TreeCount == 0)
	{
		VfsMountTreeDeleteObjects(ProcessList, StackID);
		return TRUE;
	}
	
	printf("Arbre des systemes de fichiers (%d) :\n", TreeCount);
	
	//Recuperer le noeud de tete
	pPosition = LinkListGetHeadPosition(ProcessList);
	pTree = (VfsMountTree_t *)LinkListGetNext(ProcessList, &pPosition);
	while(pTree != NULL)
	{//Explorer la liste
		VfsMountDrawVerticalLines(pTree, StackID);//Tracer les lignes verticales
		//Memoriser le niveau lors d'une double connexion (Fille et Soeur)
		if((IsSet(pTree->Status, MOUNT_BROTHER_PRESENT))&&(IsSet(pTree->Status, MOUNT_CHILD_PRESENT)))
		{//Si soeur et fille presente, memoriser le niveau
			if(LinkListAddTail(StackID, (void *)pTree->Level) == NULL)
			{//Memoire insuffisante
				VfsMountTreeDeleteObjects(ProcessList, StackID);
				SetLastError(INSUFFICIENT_MEMORY_AVAILABLE);
				return ERROR;
			}
		}
		//Machine d'etat du trace des traits
		if(pTree->Level == 0)
		{//Ne rien faire
			pSign = (char *)MSignNone;
		}
		else if((!IsSet(PrevStatus, MOUNT_BROTHER_PRESENT))&&(IsSet(pTree->Status, MOUNT_BROTHER_PRESENT)))
		{//Noeud precedent n'a pas de soeur, le courant en a une
			pSign = (char *)MSignF;
		}
		else if(!IsSet(pTree->Status, MOUNT_BROTHER_PRESENT))
		{//Noeud precedent a une soeur, pas le courant
			pSign = (char *)MSignZ;
		}
		else if(!IsSet(PrevStatus, MOUNT_BROTHER_PRESENT))
		{
			pSign = (char *)MSignZ;
		}
		else
		{
			pSign = (char *)MSignF;
		}
		PrevStatus = pTree->Status;
		//Afficher la ou les branches et le nom
		printf("%s%s\n", pSign, pTree->pName);
		//Changer d'element	
		pTree = (VfsMountTree_t *)LinkListGetNext(ProcessList, &pPosition);
		
		Line = (Line + 1) % 20;//20 equivaut au nombre de ligne sur la console
		if((Line == 0)&&(pTree != NULL))
		{//Demander a l'utilisateur de presser une touche pour voir la suite de l'ecran
			if(Pause() != TRUE)
			{//L'utilisateur stoppe la visualisation
				while(pTree != NULL)
				{//Explorer la liste pour supprimer tout les noeuds
					VfsMountTreeDeleteObjects(ProcessList, StackID);
					
					return TRUE;
				}
			}
		}
	}

	VfsMountTreeDeleteObjects(ProcessList, StackID);
	
	return TRUE;
}


//*****************************************************************************
// But de la procedure : Tracer les traits verticaux
// Entrees :
//	pTree : Pointeur sur le noeud a visualiser
//	StackID : Numero d'identification de la "pile"
// Sortie : Aucune
//*****************************************************************************
static void VfsMountDrawVerticalLines(VfsMountTree_t * pTree, LinkListID_t StackID)
{
	const char MSignI[] = {0xB3, ' ', ' ', ' ', '\0'};// |
	const char MSignSpace[] = "    ";
	Status_t Status;
	unsigned int I, OldLevel, Level;
	LNode_t * pStackPos;
	LNode_t * pOldStackPos;
	char * pSign;
	
	for(I = 1; I < pTree->Level; I++)
	{//
		OldLevel = 0;
		Status = FALSE;
		pStackPos = LinkListGetHeadPosition(StackID);
		while(pStackPos != NULL)
		{//Explorer la liste des niveaux
			pOldStackPos = pStackPos;
			Level = (int)LinkListGetNext(StackID, &pStackPos);
			if(Level == OldLevel)
			{//Niveau identique, supprimer le noeud courant
				LinkListRemoveAt(StackID, pOldStackPos);	
			}	
			if(I == Level)
			{//Tracer un trait vertical
				Status = TRUE;
				break;
			}
			OldLevel = Level;
		}
		if(Status == TRUE)
		{//Tracer un trait vertical
			pSign = (char *)MSignI;
		}
		else pSign = (char *)MSignSpace;//Ne pas tracer de trait
	
		printf(pSign);
	}
	if(!IsSet(pTree->Status, (MOUNT_BROTHER_PRESENT + MOUNT_CHILD_PRESENT)))
	{//Supprimer le niveau si le noeud n'a ni soeur ni enfant
		LinkListRemoveTail(StackID);
	}
}

//*****************************************************************************
// But de la procedure : Detruire les objets utilise pour la construction de
// l'arbre
// Entrees :
//	MountList : Numero d'identification de la liste des systemes de fichiers
//	StackID : Numero d'identification de la "pile"
// Sortie : Aucune
//*****************************************************************************
static void VfsMountTreeDeleteObjects(LinkListID_t MountList, LinkListID_t StackID)
{
	LNode_t * pPosition;
	VfsMountTree_t * pTree;

	pPosition = LinkListGetHeadPosition(MountList);
	pTree = (VfsMountTree_t *)LinkListGetNext(MountList, &pPosition);
	while(pTree != NULL)
	{//Explorer la liste pour supprimer tout les noeuds
		kfree(pTree->pName);
		kfree(pTree);
		pTree = (VfsMountTree_t *)LinkListGetNext(MountList, &pPosition);
	}
	LinkListDelete(&MountList);
	LinkListDelete(&StackID);
}

//*****************************************************************************
